#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
@File   : test09_domain.py
@Time : 2025/2/25 9:31
@Author: Wangwc
@Describe:  ……
"""
import random
import time
import pytest
import allure

from business.DomainApi import DomainApi
from business.NetworkApi import NetworkApi
from utils.login import Login
from commons.logger import log
from utils.config_tools import Config

# TODO 当前模块的配置文件名称，配置在config目录下
config_name = "user.ini"
login = Login(config_name=config_name)
config = Config(config_name=config_name)


# 全局变量存储 token
global_token = None

def get_token():
    global global_token
    if global_token is None:
        global_token = login.login()
    return global_token

@pytest.fixture(scope="function")
def domain_api():
    token = get_token()
    api = DomainApi(token, configname=config_name)
    return api

@pytest.fixture(scope="function")
def network_api():
    """
    用于初始化NetworkApi客户端的夹具
    """
    token = get_token()
    api = NetworkApi(token,configname=config_name)
    return api


def handle_api_call(api_method, *args, attach_to_allure=True, format_result=None, **kwargs):
    if not callable(api_method):
        raise TypeError("api_method 参数必须是可调用对象（如函数或方法）")
    if attach_to_allure is not None and not isinstance(attach_to_allure, bool):
        raise TypeError("attach_to_allure 参数必须是布尔类型或者为 None")
    if format_result is not None and not callable(format_result):
        raise TypeError("format_result 参数必须是可调用对象（如函数）或者为 None")

    max_retries = 3
    for retry in range(max_retries):
        try:
            result = api_method(*args, **kwargs)
            if attach_to_allure:
                if format_result:
                    formatted_result = format_result(result)
                else:
                    formatted_result = str(result)
                allure.attach(formatted_result, f"{api_method.__name__} 调用结果", allure.attachment_type.TEXT)
            log.info(f"{api_method.__name__} 调用成功")
            return result
        except Exception as e:
            allure.attach(str(e), f"{api_method.__name__} 调用错误信息", allure.attachment_type.TEXT)
            log.error(f"{api_method.__name__} 调用出现错误: {e}", exc_info=True)
            # 假设根据错误信息判断 token 过期
            if "token 过期" in str(e) and retry < max_retries - 1:
                global global_token
                global_token = login.login()
                api_method.__self__.token = global_token
                continue
            elif isinstance(e, ConnectionError):
                log.error("连接错误，可能是网络问题，请检查网络连接。")
            elif isinstance(e, ValueError):
                log.error("值错误，可能是传入的参数有误，请检查参数。")
            raise

@allure.feature("控制面板-域")
class TestDomain():
    @allure.title("加入域")
    def test_join_domain(self, domain_api):
        log.info("开始执行测试用例：加入域")
        with allure.step("读取配置信息"):
            addr = config.read_config_ini('domain', 'addr')
            dns_addr = config.read_config_ini('domain', 'dns_addr')
            account = config.read_config_ini('domain', 'account')
            password = config.read_config_ini('domain', 'password')

        with allure.step("加入域测试"):
            result = handle_api_call(domain_api.join_domain_test,addr,dns_addr, account, password)
            assert result == 'ok', "加入域测试失败"


        with allure.step("加入域"):
            results = handle_api_call(domain_api.get_domain_test_result)
            if results.get('failed') == False:
                result = handle_api_call(domain_api.join_domain, addr, dns_addr, account, password)
                assert result == 'ok', "加入域失败"

        with allure.step("查询域配置-确认成功加入域"):
            if handle_api_call(domain_api.check_domain_status,status=2):
                results = handle_api_call(domain_api.get_domain_join_config)
                assert results.get('domain_name') == addr.upper(),f"加入域失败，预期域服务器：{addr}，实际域服务器：{results.get('domain_name')}"
                assert results.get('dns_addr') == dns_addr,f"加入域失败，预期域服务器IP：{dns_addr}，实际域服务器IP：{results.get('dns_addr')}"


    @allure.title("更改域高级设置")
    def test_change_domain_config(self, domain_api):
        log.info("开始执行测试用例：更改域高级设置")
        with allure.step("获取域高级设置信息"):
            results = handle_api_call(domain_api.get_domain_join_config)
            update_period = results.get('update_period')

        with allure.step("更改域高级设置"):
            set_update_period = random.randint(120,1440)
            handle_api_call(domain_api.update_domain_config, update_period=set_update_period)
            time.sleep(10)

        with allure.step("再次获取域高级设置信息"):
            new_results = handle_api_call(domain_api.get_domain_join_config)
            new_update_period = new_results.get('update_period')
            assert new_update_period == set_update_period, f"更改域高级设置失败，预期更新周期：{set_update_period}，实际更新周期：{new_update_period}"

    @allure.title("更新域数据")
    def test_update_domain_date(self, domain_api):
        log.info("开始执行测试用例：更新域数据")
        with allure.step("获取用户信息"):
            time.sleep(5)
            results = handle_api_call(domain_api.get_domain_userlist)
            user_list = results.get('list')

        with allure.step("更新域数据"):
            result = handle_api_call(domain_api.update_domain_data)
            assert result == 'ok', "更新域数据失败"
            time.sleep(5)

        with allure.step("获取更新域数据后的用户信息"):
            new_results = handle_api_call(domain_api.get_domain_userlist)
            new_user_list = new_results.get('list')
            assert len(new_user_list) >= len(user_list), "更新域数据失败，用户数量不一致"

    @allure.title("域用户搜索")
    def test_search_user(self, domain_api):
        log.info("开始执行测试用例：域用户搜索")
        with allure.step("获取用户信息"):
            results = handle_api_call(domain_api.get_domain_userlist)
            user_list = results.get('list')
            username = user_list[random.randint(0,len(user_list)-1)].get('username')

        with allure.step("精确搜索用户"):
            ex_result = handle_api_call(domain_api.get_domain_userlist,keyword=username)
            ex_user_list = ex_result.get('list')
            assert ex_user_list[0].get('username') == username,f"精确搜索域用户失败，预期用户名：{username}，实际用户名：{ex_user_list.get('username')}"

        with allure.step("错误搜索用户名"):
            err_results = handle_api_call(domain_api.get_domain_userlist,keyword=f"{username}12345678")
            assert err_results.get('list') == [], f"错误搜索域用户失败，预期用户列表为空，实际用户列表为：{err_results.get('list')}"

    @allure.title("编辑域用户信息")
    def test_edit_user_info(self, domain_api):
        log.info("开始执行测试用例：编辑域用户信息")
        with allure.step("获取用户列表信息"):
            results = handle_api_call(domain_api.get_domain_userlist)
            user_list = results.get('list')
            uid = user_list[random.randint(0, len(user_list)-1)].get('uid')

        with allure.step("获取域用户信息"):
            user_info = handle_api_call(domain_api.get_domain_user_info, uid)
            enable_home_dir = user_info.get('enable_home_dir')
            username = user_info.get('username')
            role = user_info.get('role')
            unit = user_info.get('unit')
            dir_quota = user_info.get('dir_quota')

        with allure.step("编辑域用户信息"):
            set_enable_home_dir = True if enable_home_dir == False else False
            result = handle_api_call(domain_api.edit_domain_user_info, uid,username,role=role,enable_home_dir=set_enable_home_dir, unit=unit, dir_quota=dir_quota)
            assert result == 'ok', "编辑域用户信息失败"

        with allure.step("再次获取用户信息"):
            new_user_info = handle_api_call(domain_api.get_domain_user_info, uid)
            new_enable_home_dir = new_user_info.get('enable_home_dir')
            assert new_enable_home_dir == set_enable_home_dir, f"编辑域用户信息失败，预期enable_home_dir：{set_enable_home_dir}，实际enable_home_dir：{new_enable_home_dir}"

    @allure.title("域用户组搜索")
    def test_search_group(self, domain_api):
        log.info("开始执行测试用例：域用户组搜索")
        with allure.step("获取用户组信息"):
            results = handle_api_call(domain_api.get_domain_grouplist)
            group_list = results.get('list')
            groupname = group_list[random.randint(0, len(group_list)-1)].get('groupname')

        with allure.step("精确搜索用户组"):
            ex_result = handle_api_call(domain_api.get_domain_grouplist, keyword=groupname)
            ex_group_list = ex_result.get('list')
            assert ex_group_list[0].get(
                'groupname') == groupname, f"精确搜索域用户组失败，预期用户组名：{groupname}，实际用户组名：{ex_group_list.get('groupname')}"

        with allure.step("错误搜索用户组名"):
            err_results = handle_api_call(domain_api.get_domain_grouplist, keyword=f"{groupname}123")
            assert err_results.get('list') == [], f"错误搜索域用户组失败，预期用户组列表为空，实际用户组列表为：{err_results.get('list')}"

    @allure.title("编辑域用户组信息")
    def test_edit_group_info(self, domain_api):
        log.info("开始执行测试用例：编辑域用户组信息")
        with allure.step("获取域用户组列表信息"):
            results = handle_api_call(domain_api.get_domain_grouplist)
            group_list = results.get('list')
            gid = group_list[random.randint(0,len(group_list)-1)].get('gid')
            log.info(f"获取到的域用户组id为：{gid}")

        with allure.step("获取域用户组权限信息"):
            group_permission = handle_api_call(domain_api.get_domain_group_permission, gid)
            permssion_list = [{'path':item.get('path'), 'permission':item.get('permission')} for item in group_permission]
            log.info(f"刚开始获取的域用户组权限列表：{permssion_list}")
            permssion_list[0]['permission'] = 7 if permssion_list[0]['permission'] == -1 else 0
            set_permssion_list = permssion_list
            log.info(f"编辑后的域用户组权限列表：{set_permssion_list}")


        with allure.step("编辑域用户组权限信息"):
            handle_api_call(domain_api.edit_domain_group_permission, gid, set_permssion_list)
            time.sleep(5)

        with allure.step("再次获取域用户组信息"):
            new_group_permission = handle_api_call(domain_api.get_domain_group_permission, gid)
            new_permssion_list = [{'path': item.get('path'), 'permission': item.get('permission')} for item in
                              new_group_permission]
            log.info(f"编辑后获取的域用户组权限列表：{new_permssion_list}")
            assert sorted(set_permssion_list, key=lambda x: x['path']) == sorted(new_permssion_list, key=lambda x: x['path']), f"编辑域用户组权限失败，预期用户组权限列表：{set_permssion_list}，实际用户组权限列表：{new_permssion_list}"


    @allure.title("退出域")
    def test_exit_domain(self, domain_api):
        log.info("开始执行测试用例：退出域")
        with allure.step("获取域设置信息"):
            results = handle_api_call(domain_api.get_domain_join_config)
            assert results.get("account") != ''

        with allure.step("获取x_curpass_token"):
            password = config.read_config_ini('user','user_pwd')
            rsa_token = login.verify_check()
            x_curpass_token = login.data_encrypt.rsa_passwd(rsa_token, password)

        with allure.step("退出域"):
            handle_api_call(domain_api.exit_domain,x_curpass_token)
            time.sleep(5)

        with allure.step("再次获取域设置信息"):
            if handle_api_call(domain_api.check_domain_status,status=0):
                new_results = handle_api_call(domain_api.get_domain_join_config)
                assert new_results.get('account') == '', f"退出域失败，预期用户为空，实际用户为：{new_results.get('account')}"

    @allure.title("加入LDAP域")
    def test_join_ldap_domain(self, domain_api):
        log.info("开始执行测试用例：加入LDAP域")
        with allure.step("读取配置信息"):
            time.sleep(20)
            ldap_addr = config.read_config_ini('domain', 'ldap_addr')
            ldap_dns_addr = config.read_config_ini('domain', 'ldap_dns_addr')
            ldap_account = config.read_config_ini('domain', 'ldap_account')
            ldap_password = config.read_config_ini('domain', 'ldap_password')
            ldap_base_dn = config.read_config_ini('domain', 'ldap_base_dn')

        with allure.step("加入LDAP域测试"):
            result = handle_api_call(domain_api.join_domain_test, ldap_addr, ldap_dns_addr, ldap_account, ldap_password,domain_type=1,base_dn=ldap_base_dn)
            assert result == 'ok', "加入LDAP域测试失败"

        with allure.step("加入LDAP域"):
            results = handle_api_call(domain_api.get_domain_test_result)
            if results.get('failed') == False:
                result = handle_api_call(domain_api.join_domain, ldap_addr, ldap_dns_addr, ldap_account, ldap_password,domain_type=1,base_dn=ldap_base_dn)
                assert result == 'ok', "加入LDAP域失败"

        with allure.step("查询域配置-确认成功加入域"):
            if handle_api_call(domain_api.check_domain_status):
                results = handle_api_call(domain_api.get_domain_join_config)
                assert results.get(
                    'addr') == ldap_addr, f"加入域失败，预期域服务器：{ldap_addr}，实际域服务器：{results.get('addr')}"
                assert results.get('dns_addr') == ldap_dns_addr, f"加入域失败，预期域服务器IP：{ldap_dns_addr}，实际域服务器IP：{results.get('dns_addr')}"

    @allure.title("更改LDAP域高级设置")
    def test_change_ldap_domain_config(self, domain_api):
        log.info("开始执行测试用例：更改LDAP域高级设置")
        with allure.step("获取LDAP域高级设置信息"):
            results = handle_api_call(domain_api.get_domain_join_config)
            update_period = results.get('update_period')

        with allure.step("更改LDAP域高级设置"):
            set_update_period = random.randint(120,1440)
            handle_api_call(domain_api.update_domain_config, update_period=set_update_period)
            time.sleep(5)

        with allure.step("再次获取LDAP域高级设置信息"):
            new_results = handle_api_call(domain_api.get_domain_join_config)
            new_update_period = new_results.get('update_period')
            assert new_update_period == set_update_period, f"更改LDAP域高级设置失败，预期更新周期：{set_update_period}，实际更新周期：{new_update_period}"

    @allure.title("更新LDAP域数据")
    def test_update_ldap_domain_date(self, domain_api):
        log.info("开始执行测试用例：更新LDAP域数据")
        with allure.step("获取用户信息"):
            time.sleep(20)
            results = handle_api_call(domain_api.get_domain_userlist)
            user_list = results.get('list')

        with allure.step("更新域数据"):
            result = handle_api_call(domain_api.update_domain_data)
            assert result == 'ok', "更新域数据失败"
            time.sleep(20)

        with allure.step("获取更新域数据后的用户信息"):
            new_results = handle_api_call(domain_api.get_domain_userlist)
            new_user_list = new_results.get('list')
            assert len(new_user_list) >= len(user_list), "更新域数据失败，用户数量不一致"

    @allure.title("LDAP域用户搜索")
    def test_search_ldap_user(self, domain_api):
        log.info("开始执行测试用例：LDAP域用户搜索")
        with allure.step("获取用户信息"):
            results = handle_api_call(domain_api.get_domain_userlist)
            user_list = results.get('list')
            username = user_list[random.randint(0,len(user_list)-1)].get('username')

        with allure.step("精确搜索用户"):
            ex_result = handle_api_call(domain_api.get_domain_userlist,keyword=username)
            ex_user_list = ex_result.get('list')
            assert ex_user_list[0].get('username') == username,f"精确搜索域用户失败，预期用户名：{username}，实际用户名：{ex_user_list.get('username')}"

        with allure.step("错误搜索用户名"):
            err_results = handle_api_call(domain_api.get_domain_userlist,keyword=f"{username}128545858")
            assert err_results.get('list') == [], f"错误搜索域用户失败，预期用户列表为空，实际用户列表为：{err_results.get('list')}"

    @allure.title("编辑LDAP域用户信息")
    def test_edit_ldap_user_info(self, domain_api):
        log.info("开始执行测试用例：编辑LDAP域用户信息")
        with allure.step("获取LDAP域用户列表信息"):
            results = handle_api_call(domain_api.get_domain_userlist)
            user_list = results.get('list')
            uid = user_list[random.randint(0, len(user_list)-1)].get('uid')

        with allure.step("获取LDAP域用户信息"):
            user_info = handle_api_call(domain_api.get_domain_user_info, uid)
            enable_home_dir = user_info.get('enable_home_dir')
            username = user_info.get('username')
            unit = user_info.get('unit')
            dir_quota = user_info.get('dir_quota')
            role = user_info.get('role')

        with allure.step("编辑LDAP域用户信息"):
            set_enable_home_dir = True if enable_home_dir == False else False
            result = handle_api_call(domain_api.edit_domain_user_info, uid,username,role=role, enable_home_dir=set_enable_home_dir, unit=unit, dir_quota=dir_quota)
            assert result == 'ok', "编辑LDAP域用户信息失败"

        with allure.step("再次获取LDAP域用户信息"):
            new_user_info = handle_api_call(domain_api.get_domain_user_info, uid)
            new_enable_home_dir = new_user_info.get('enable_home_dir')
            assert new_enable_home_dir == set_enable_home_dir, f"编辑LDAP域用户信息失败，预期enable_home_dir：{set_enable_home_dir}，实际enable_home_dir：{new_enable_home_dir}"

    @pytest.mark.skip(reason = "当前LDAP域用户组为空，暂时无需执行")
    @allure.title("LDAP域用户组搜索")
    def test_search_ldap_group(self, domain_api):
        log.info("开始执行测试用例：LDAP域用户组搜索")
        with allure.step("获取用户组信息"):
            results = handle_api_call(domain_api.get_domain_grouplist)
            group_list = results.get('list')
            groupname = group_list[random.randint(0, len(group_list)-1)].get('groupname')

        with allure.step("精确搜索用户组"):
            ex_result = handle_api_call(domain_api.get_domain_grouplist, keyword=groupname)
            ex_group_list = ex_result.get('list')
            assert ex_group_list[0].get(
                'groupname') == groupname, f"精确搜索域用户组失败，预期用户组名：{groupname}，实际用户组名：{ex_group_list.get('groupname')}"

        with allure.step("错误搜索用户组名"):
            err_results = handle_api_call(domain_api.get_domain_grouplist, keyword=f"{groupname}123")
            assert err_results.get('list') == [], f"错误搜索域用户组失败，预期用户组列表为空，实际用户组列表为：{err_results.get('list')}"

    @pytest.mark.skip(reason = "当前LDAP域用户组为空，暂时无需执行")
    @allure.title("编辑LDAP域用户组信息")
    def test_edit_ldap_group_info(self, domain_api):
        log.info("开始执行测试用例：编辑LDAP域用户组信息")
        with allure.step("获取用户组列表信息"):
            results = handle_api_call(domain_api.get_domain_grouplist)
            group_list = results.get('list')
            gid = group_list[random.randint(0,len(group_list)-1)].get('gid')
            log.info(f"获取到的用户组id为：{gid}")

        with allure.step("获取用户组权限信息"):
            group_permission = handle_api_call(domain_api.get_domain_group_permission, gid)
            permssion_list = [{'path':item.get('path'), 'permission':item.get('permission')} for item in group_permission]
            log.info(f"刚开始获取的用户组权限列表：{permssion_list}")
            permssion_list[0]['permission'] = 7 if permssion_list[0]['permission'] == -1 else 0
            set_permssion_list = permssion_list
            log.info(f"编辑后的用户组权限列表：{set_permssion_list}")


        with allure.step("编辑用户组权限信息"):
            handle_api_call(domain_api.edit_domain_group_permission, gid, set_permssion_list)
            time.sleep(5)

        with allure.step("再次获取用户组信息"):
            new_group_permission = handle_api_call(domain_api.get_domain_group_permission, gid)
            new_permssion_list = [{'path': item.get('path'), 'permission': item.get('permission')} for item in
                              new_group_permission]
            log.info(f"编辑后获取的用户组权限列表：{new_permssion_list}")
            assert sorted(set_permssion_list, key=lambda x: x['path']) == sorted(new_permssion_list, key=lambda x: x['path']), f"编辑域用户组权限失败，预期用户组权限列表：{set_permssion_list}，实际用户组权限列表：{new_permssion_list}"

    @allure.title("退出LDAP域")
    def test_exit_ldap_domain(self, domain_api,network_api):
        log.info("开始执行测试用例：退出LDAP域")
        with allure.step("获取LDAP域设置信息"):
            results = handle_api_call(domain_api.get_domain_join_config)
            assert results.get("account") != ''

        with allure.step("获取x_curpass_token"):
            password = config.read_config_ini('user', 'user_pwd')
            rsa_token = login.verify_check()
            x_curpass_token = login.data_encrypt.rsa_passwd(rsa_token, password)

        with allure.step("退出LDAP域"):
            handle_api_call(domain_api.exit_domain, x_curpass_token)
            time.sleep(10)

        with allure.step("再次获取LDAP域设置信息"):
            if handle_api_call(domain_api.check_domain_status,status=0):
                new_results = handle_api_call(domain_api.get_domain_join_config)
                assert new_results.get('account') == '', f"退出LDAP域失败，预期用户为空，实际用户为：{new_results.get('account')}"

        with allure.step("恢复DNS服务器为自动获取"):
            results = handle_api_call(network_api.get_network_general)
            general = results.get('general')
            proxy = results.get('proxy')
            general['dns_mode'] = 0
            handle_api_call(network_api.set_network_general, general, proxy)